/*
 * @Author: i@rysa.cn
 * @Date: 2022-05-14 16:43:03
 * @LastEditTime: 2022-05-14 16:46:52
 * @LastEditors: i@rysa.cn
 * @Description:
 * @FilePath: \go-utils\wechat\utils\tools.go
 */
package utils

import (
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

func StructToMap(value interface{}, tagName string) (map[string]interface{}, error) {
	v := reflect.ValueOf(value)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
	}
	t := v.Type()
	out := make(map[string]interface{})
	for i := 0; i < v.NumField(); i++ {
		fi := t.Field(i)
		if tagValue := fi.Tag.Get(tagName); tagValue != "" {
			ss := v.Field(i).Interface()
			switch stype := reflect.TypeOf(ss); stype.Kind() {
			case reflect.Int:
			case reflect.Int64:
				if ss == 0 {
					continue
				}
				out[tagValue] = ss
			case reflect.String:
				if ss == "" {
					continue
				}
				out[tagValue] = ss
			}
		}
	}
	return out, nil
}

func GetWechatSign(data interface{}, tagName, key string) (string, error) {
	out, err := StructToMap(data, tagName)
	if err != nil {
		return "", err
	}
	keys := make([]string, len(out))
	j := 0
	for i := range out {
		keys[j] = i
		j++
	}
	sort.Slice(keys, func(i, j int) bool {
		return keys[i] < keys[j]
	})
	var buf strings.Builder
	for _, v := range keys {
		if t, ok := out[v]; ok {
			buf.WriteString(v)
			buf.WriteByte('=')
			switch stype := reflect.TypeOf(t); stype.Kind() {
			case reflect.Int:
				buf.WriteString(strconv.Itoa(t.(int)))
			case reflect.Int64:
				buf.WriteString(strconv.FormatInt(t.(int64), 10))
			case reflect.String:
				buf.WriteString(t.(string))
			}
			buf.WriteString("&")
		}
	}
	if len(key) > 0 {
		buf.WriteString("key")
		buf.WriteByte('=')
		buf.WriteString(key)
		buf.WriteString("&")
	}
	s := strings.TrimSuffix(buf.String(), "&")
	return s, nil
}
